<template>
  <div id="three" class="w-p-100 h-p-100 relative">
    <div
      id="getBoundingClientRect"
      ref="threeJsContainer"
      class="w-p-100 h-p-100"
    ></div>
    <CustomThreeCard
      v-show="isHover"
      :color="threeCardColor"
      :title="threeCardTitle"
      :value="threeCardValue"
      id="threeCard"
      class="title absolute"
    ></CustomThreeCard>
  </div>
</template>

<script setup>
import * as THREE from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
// 引入CSS2渲染器CSS2DRenderer和CSS2模型对象CSS2DObject
import {
  CSS2DRenderer,
  CSS2DObject,
} from "three/addons/renderers/CSS2DRenderer.js";

import { DragControls } from "three/examples/jsm/controls/DragControls";

import { onMounted, ref } from "vue";

import CustomThreeCard from "@/components/CustomThreeCard/index.vue";

let scene,
  camera,
  renderer,
  css2Renderer,
  controls,
  dragControls,
  glbModel,
  cardObjects;
const threeJsContainer = ref();
const threeCardColor = ref("");
const threeCardTitle = ref("");
const threeCardValue = ref("");
const isHover = ref(false);
onMounted(() => {
  initThree();
});

const initThree = () => {
  // 创建场景
  scene = new THREE.Scene();

  // 创建相机
  camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  );
  camera.position.x = 2.9;
  camera.position.y = 2.83;
  camera.position.z = -2.64;

  let ambientLight = new THREE.AmbientLight(0xffffff, 1); // 创建环境光
  // 平行光
  let directionalight = new THREE.DirectionalLight(0xffffff, 4);
  directionalight.position.set(5, 15, -1);
  scene.add(directionalight);
  //   scene.add(ambientLight) // 将环境光添加到场景

  // 创建渲染器
  renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setClearColor(0x333, 1); // 设置背景颜色
  renderer.setSize(
    threeJsContainer.value.clientWidth,
    threeJsContainer.value.clientHeight
  );
  threeJsContainer.value.appendChild(renderer.domElement);

  // 创建一个CSS2渲染器CSS2DRenderer
  css2Renderer = new CSS2DRenderer();
  css2Renderer.setSize(
    threeJsContainer.value.clientWidth,
    threeJsContainer.value.clientHeight
  );
  threeJsContainer.value.appendChild(css2Renderer.domElement);

  controls = new OrbitControls(camera, renderer.domElement);
  controls.target.set(-1.8, -0.7, 0);
  controls.update();

  controls.enableDamping = true;

  controls.enableZoom = true;

  controls.enablePan = true;

  // 加载GLB模型
  loadGLBModel();
  loadTitle();

  // 渲染场景
  animate();
};

const loadGLBModel = () => {
  const loader = new GLTFLoader();
  loader.load("./model1.glb", (gltf) => {
    glbModel = gltf.scene;
    glbModel.traverse((child) => {
      // console.log(child);
      if (child.isMesh) {
        // 创建一个新的材质
        let material = new THREE.MeshStandardMaterial({
          color: "#0076DD",
          transparent: true, // 开启透明度
          opacity: 1, // 设置透明度为0.8
        });
        //   let material = new THREE.MeshBasicMaterial({
        //   color: "#14B0FF", // 设置颜色为#14B0FF
        //   transparent: true, // 开启透明度
        //   opacity: 0.3 // 设置透明度为0.9
        // });

        // 应用新的材质到子对象上
        child.material = material;
      }
    });
    scene.add(glbModel);
  });
};
// 模拟卡片位置和报警等级，根据实际调整
const canvasPositon = [
  { x: 0.5, y: 1.1, z: 1.7, al: 0, title: "建筑A", value: "23454323" },
  { x: -1, y: 2.0, z: 2.6, al: 1, title: "建筑B", value: "23454323" },
  { x: -1, y: 1.1, z: -2, al: 2, title: "建筑C", value: "23454323" },
  { x: -1.1, y: 1.8, z: -0.5, al: 3, title: "建筑D", value: "23454323" },
];

// 创建不同等级对应卡片的类型
const titleColorObj = {
  0: "./img/green.png",
  1: "./img/yellow.png",
  2: "./img/orange.png",
  3: "./img/red.png",
};
const loadTitle = () => {
  const texLoader = new THREE.TextureLoader();
  cardObjects = [];
  canvasPositon.forEach((val) => {
    const texture = texLoader.load(titleColorObj[val.al]);
    const spriteMaterial = new THREE.SpriteMaterial({
      map: texture,
    });
    const sprite = new THREE.Sprite(spriteMaterial);
    sprite.scale.set(0.6, 0.6, 0.6);
    sprite.position.set(val.x, val.y, val.z);
    sprite.al = val.al;
    sprite.title = val.title;
    sprite.value = val.value;
    cardObjects.push(sprite);
    scene.add(sprite);
  });

  setDragControls();
};

// 不同报警等级对应的颜色
const cardColorObj = ["#39F3FE", "#F4E522", "#F47423", "#FF003A"];
// 鼠标移入显示的标识牌的位置
const setLabelStyle = (x1, y1, z1, al, title, value) => {
  let div = document.getElementById("threeCard");
  const { width, height } = threeJsContainer.value.getBoundingClientRect();
  let worldVector = new THREE.Vector3(x1, y1, z1);
  let vector = worldVector.project(camera);
  //
  let halfWidth = width / 2,
    halfHeight = height / 2;
  // 将三维坐标转为屏幕坐标
  let x = Math.round(vector.x * halfWidth + halfWidth);
  let y = Math.round(-vector.y * halfHeight + halfHeight);
  div.style.left = x + "px";
  div.style.top = y - 90 + "px";
  threeCardColor.value = cardColorObj[al];
  threeCardTitle.value = title;
  threeCardValue.value = value;
  div = null;
  worldVector = null;
  vector = null;
};

// 设置鼠标移入事件
const setDragControls = () => {
  dragControls = new DragControls(cardObjects, camera, renderer.domElement);
  dragControls.addEventListener("hoveron", (event) => {
    let object = event.object;
    if (object) {
      isHover.value = true;
      setLabelStyle(
        object.position.x,
        object.position.y,
        object.position.z,
        object.al,
        object.title,
        object.value
      );
    }
  });

  dragControls.addEventListener("hoveroff", () => {
    isHover.value = false;
  });
};

const animate = () => {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
  css2Renderer.render(scene, camera);
};
</script>

<style scoped>
.title {
  right: 50%;
  top: 30%;
}
</style>